﻿using System;
using System.Collections.Generic;
using GeoAPI.Geometries;

namespace NetTopologySuite.Geometries.Utilities
{
	public class GeometryTransformer
	{
		public IGeometry InputGeometry
		{
			get
			{
				return this._inputGeom;
			}
		}

		public IGeometry Transform(IGeometry inputGeom)
		{
			this._inputGeom = inputGeom;
			this.Factory = inputGeom.Factory;
			if (inputGeom is IPoint)
			{
				return this.TransformPoint((IPoint)inputGeom, null);
			}
			if (inputGeom is IMultiPoint)
			{
				return this.TransformMultiPoint((IMultiPoint)inputGeom, null);
			}
			if (inputGeom is ILinearRing)
			{
				return this.TransformLineString((ILinearRing)inputGeom, null);
			}
			if (inputGeom is ILineString)
			{
				return this.TransformLineString((ILineString)inputGeom, null);
			}
			if (inputGeom is IMultiLineString)
			{
				return this.TransformMultiLineString((IMultiLineString)inputGeom, null);
			}
			if (inputGeom is IPolygon)
			{
				return this.TransformPolygon((IPolygon)inputGeom, null);
			}
			if (inputGeom is IMultiPolygon)
			{
				return this.TransformMultiPolygon((IMultiPolygon)inputGeom, null);
			}
			if (inputGeom is IGeometryCollection)
			{
				return this.TransformGeometryCollection((IGeometryCollection)inputGeom, null);
			}
			throw new ArgumentException("Unknown Geometry subtype: " + inputGeom.GetType().FullName);
		}

		protected virtual ICoordinateSequence CreateCoordinateSequence(Coordinate[] coords)
		{
			return this.Factory.CoordinateSequenceFactory.Create(coords);
		}

		protected virtual ICoordinateSequence Copy(ICoordinateSequence seq)
		{
			return (ICoordinateSequence)seq.Clone();
		}

		protected virtual ICoordinateSequence TransformCoordinates(ICoordinateSequence coords, IGeometry parent)
		{
			return this.Copy(coords);
		}

		protected virtual IGeometry TransformPoint(IPoint geom, IGeometry parent)
		{
			return this.Factory.CreatePoint(this.TransformCoordinates(geom.CoordinateSequence, geom));
		}

		protected virtual IGeometry TransformMultiPoint(IMultiPoint geom, IGeometry parent)
		{
			List<IGeometry> list = new List<IGeometry>();
			for (int i = 0; i < geom.NumGeometries; i++)
			{
				IGeometry geometry = this.TransformPoint((IPoint)geom.GetGeometryN(i), geom);
				if (geometry != null && !geometry.IsEmpty)
				{
					list.Add(geometry);
				}
			}
			return this.Factory.BuildGeometry(list);
		}

		protected virtual IGeometry TransformLinearRing(ILinearRing geom, IGeometry parent)
		{
			ICoordinateSequence coordinateSequence = this.TransformCoordinates(geom.CoordinateSequence, geom);
			if (coordinateSequence == null)
			{
                return this.Factory.CreateLinearRing((ICoordinateSequence)null);
			}
			int count = coordinateSequence.Count;
			if (count > 0 && count < 4 && !this._preserveType)
			{
				return this.Factory.CreateLineString(coordinateSequence);
			}
			return this.Factory.CreateLinearRing(coordinateSequence);
		}

		protected virtual IGeometry TransformLineString(ILineString geom, IGeometry parent)
		{
			return this.Factory.CreateLineString(this.TransformCoordinates(geom.CoordinateSequence, geom));
		}

		protected virtual IGeometry TransformMultiLineString(IMultiLineString geom, IGeometry parent)
		{
			List<IGeometry> list = new List<IGeometry>();
			for (int i = 0; i < geom.NumGeometries; i++)
			{
				IGeometry geometry = this.TransformLineString((ILineString)geom.GetGeometryN(i), geom);
				if (geometry != null && !geometry.IsEmpty)
				{
					list.Add(geometry);
				}
			}
			return this.Factory.BuildGeometry(list);
		}

		protected virtual IGeometry TransformPolygon(IPolygon geom, IGeometry parent)
		{
			bool flag = true;
			IGeometry geometry = this.TransformLinearRing(geom.Shell, geom);
			if (geometry == null || !(geometry is ILinearRing) || geometry.IsEmpty)
			{
				flag = false;
			}
			List<ILineString> list = new List<ILineString>();
			for (int i = 0; i < geom.NumInteriorRings; i++)
			{
				IGeometry geometry2 = this.TransformLinearRing(geom.Holes[i], geom);
				if (geometry2 != null && !geometry2.IsEmpty)
				{
					if (!(geometry2 is ILinearRing))
					{
						flag = false;
					}
					list.Add((ILineString)geometry2);
				}
			}
			if (flag)
			{
				ILinearRing[] holes = list.ConvertAll<ILinearRing>((ILineString ls) => (ILinearRing)ls).ToArray();
				return this.Factory.CreatePolygon((ILinearRing)geometry, holes);
			}
			List<IGeometry> list2 = new List<IGeometry>();
			if (geometry != null)
			{
				list2.Add(geometry);
			}
			foreach (IGeometry item in list)
			{
				list2.Add(item);
			}
			return this.Factory.BuildGeometry(list2);
		}

		protected virtual IGeometry TransformMultiPolygon(IMultiPolygon geom, IGeometry parent)
		{
			List<IGeometry> list = new List<IGeometry>();
			for (int i = 0; i < geom.NumGeometries; i++)
			{
				IGeometry geometry = this.TransformPolygon((IPolygon)geom.GetGeometryN(i), geom);
				if (geometry != null && !geometry.IsEmpty)
				{
					list.Add(geometry);
				}
			}
			return this.Factory.BuildGeometry(list);
		}

		protected virtual IGeometry TransformGeometryCollection(IGeometryCollection geom, IGeometry parent)
		{
			List<IGeometry> list = new List<IGeometry>();
			for (int i = 0; i < geom.NumGeometries; i++)
			{
				IGeometry geometry = this.Transform(geom.GetGeometryN(i));
				if (geometry != null && (!this.pruneEmptyGeometry || !geometry.IsEmpty))
				{
					list.Add(geometry);
				}
			}
			if (this.preserveGeometryCollectionType)
			{
				return this.Factory.CreateGeometryCollection(GeometryFactory.ToGeometryArray(list));
			}
			return this.Factory.BuildGeometry(list);
		}

		private IGeometry _inputGeom;

		protected IGeometryFactory Factory;

		private bool pruneEmptyGeometry = true;

		private bool preserveGeometryCollectionType = true;

		private bool _preserveType;
	}
}
